import * as fs from "fs";
import * as path from "path";
import { window } from "vscode";

export default async function (filePath: string, highWaterMark: number, historyDirPath: string) {
    const { size } = await fs.promises.stat(filePath);
    const history: any = {};
    const historyPath = path.resolve(historyDirPath, `${path.basename(filePath)}.history`);
    try {
        Object.assign(history, JSON.parse(fs.readFileSync(historyPath).toString()));
    } catch (error) {
        window.showErrorMessage("历史记录文件异常, JSON解析失败！", historyPath);
    }
    history.bytesRead = history.bytesRead || 0;
    const fd = fs.openSync(filePath, 'r');
    return {
        async last() {
            let data = await openFileAsync(fd, 0, highWaterMark, history.bytesRead - highWaterMark);
            history.bytesRead -= Buffer.from(data.substr(2)).length;
            fs.promises.writeFile(historyPath, JSON.stringify(history));
            return {
                value: data.substr(2).replace(/\r\n/g, '').replace(/\n/g, ''),
                percentage: (history.bytesRead / size * 100).toFixed(2) + '%',
            };
        },
        async next() {
            let data = await openFileAsync(fd, 0, highWaterMark, history.bytesRead);
            history.bytesRead += Buffer.from(data.substr(0, data.length - 2)).length;
            fs.promises.writeFile(historyPath, JSON.stringify(history));
            return {
                value: data.substr(0, data.length - 2).replace(/\r\n/g, '').replace(/\n/g, ''),
                percentage: (history.bytesRead / size * 100).toFixed(2) + '%',
            };
        },
        async stop() {
            fs.close(fd, () => {});
        },
        async skip(percentage: number) {
            history.bytesRead = Math.round(percentage * size);
            history.bytesRead = history.bytesRead > 0 ? history.bytesRead : 0;
            let data = await openFileAsync(fd, 0, highWaterMark, history.bytesRead);
            if (history.bytesRead === 0) {
                data = data.substr(2);
                history.bytesRead -= Buffer.from(data.substr(2)).length;
            }
            history.bytesRead -= Buffer.from(data.substr(0, data.length - 2)).length;
            history.bytesRead = history.bytesRead > 0 ? history.bytesRead : 0;
            fs.promises.writeFile(historyPath, JSON.stringify(history));
            data = data.substr(0, data.length - 2);
            return {
                value: data.replace(/\r\n/g, '').replace(/\n/g, ''),
                percentage: (history.bytesRead / size * 100).toFixed(2) + '%',
            };
        }
    };
}

function openFileAsync(fd: number, offset: number, length: number, bytesRead: number): Promise<string> {
    const buffer = Buffer.alloc(length);
    return new Promise((resolve, reject) => {
        fs.read(fd, buffer, offset, length, bytesRead, (err) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(buffer.toString());
        });
    });
}
